Skip to content

CSRF(跨站请求伪造)

用户已登录站点 A,浏览器会自动带上 A 的 Cookie。攻击者诱导用户访问恶意站点 B,B 中的表单或脚本向 A 发起请求;只要 Cookie 随请求发送且 A 未校验「本次操作是否用户本意」,就可能完成转账、改密等。

说明

以下代码仅供理解原理与本地实验,请勿用于未授权系统。


攻击示意:跨站表单 POST

恶意页面(简化):

html
<!-- https://evil.example/csrf.html -->
<body>
  <form id="f" action="https://bank.example/api/transfer" method="POST">
    <input name="to" value="attacker" />
    <input name="amount" value="9999" />
  </form>
  <script>document.getElementById('f').submit();</script>
</body>

bank.example 仅依赖 Cookie 会话且接口接受简单 POST,用户在仍登录状态下打开该页即可能触发转账。

GET 场景同理: <img src="https://bank.example/api/delete?id=1"> 若服务端把敏感操作用 GET 实现且仅靠 Cookie,危害更大。


防御一:CSRF Token(前后端配合)

后端:为会话签发随机 Token,嵌入页面或接口响应。

前端:在同源 AJAX / fetch 中附带 Token。

html
<meta name="csrf-token" content="__SERVER_RENDERED_TOKEN__" />
js
const token = document.querySelector('meta[name="csrf-token"]')?.content;

await fetch('/api/transfer', {
  method: 'POST',
  credentials: 'same-origin',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': token,
  },
  body: JSON.stringify({ to: 'bob', amount: 100 }),
});

原理:跨域站点 B 读不到 A 页面里的 Token(同源策略),表单伪造无法附带正确 Token。


服务端设置 Cookie:

http
Set-Cookie: sid=...; HttpOnly; Secure; SameSite=Lax
  • Strict:完全禁止跨站携带(最安全,可能影响少数跳转登录场景)。
  • Lax(常用默认值):跨站 顶级导航 GET 仍可带 Cookie,但对多数 CSRF POST 场景有帮助。
  • 敏感操作建议仍配合 Token / 二次验证。

防御三:校验 Origin / Referer

服务端拒绝 Origin 不在白名单内的状态变更请求(注意浏览器在某些场景不发送 Referer)。


防御四:敏感操作二次确认

转账、改绑手机等要求短信验证码、密码再输入;攻击者无法替你完成第二步。


小结

手段作用
CSRF Token跨站页面拿不到 Token,请求被拒
SameSite Cookie限制跨站携带 Cookie
Origin 校验拒绝非法来源请求
二次验证即使 Cookie 被带也无法单独完成敏感操作